#coding=utf-8
import random
import os
import time
from decimal import *
import numpy as np
import matplotlib.pyplot as plt
from pylab import mpl
from utils.mylib_db import *
from utils.mylib_utils import *
from measurement.measurement_utils import *
from measurement.import_probe_data_into_db import *
from measurement.preprocess_probe_data import *
from measurement.data_analysis import *
from measurement.algorithm_gum_bak import *
import multiprocessing

EPSINON = 1e-6          # 用于浮点数比较的差值
WaitTime = 5            # 循环读取原始文件目录的时间！（秒）

db_raw_l2_data_table = "bt_data_l2_raw"                 # 原始数据L2数据表
# db_raw_l0_data_table = "bt_data_l0_raw"                 # 原始数据L0数据表

db_data_head_table = "bt_data_head"
# db_raw_l0_precessed_table = "bt_data_l0"
db_raw_l2_precessed_table = "bt_data"
db_temporary_data_head_table = "bt_temporary_data_head"
db_temporary_data_table_l2 = "bt_temporary_data"
# db_temporary_data_table_l0 = "bt_temporary_data_l0"
# db_system_parameter_config_table = "bt_system_parameter_config"

def measurementProbeData(param):
    """
    不确定度一键评定：从导入-->预处理-->不确定度评定，一条龙
    """
    print(param)
    task_id = param.get('task_id') if param.get('task_id') is not None else get_current_timestamp()                     # TaskId默认为当前时间
    user_id = int(param.get('user_id')) if param.get('user_id') is not None else -1                                     # 当前登录用户
    file_path = param.get('file_path') if param.get('file_path') is not None else ""                                    # 必填
    data_generate_source = int(param.get('data_generate_source')) if param.get('data_generate_source') is not None else 0    # 数据类型：0:地基综合探测系统（默认）；1:原位探测
    data_generate_type = int(param.get('data_generate_type')) if param.get('data_generate_type') is not None else 0          # 数据产生：0:实时数据; 1:历史数据

    # 算法参数
    measure_method = int(param.get('measure_method')) if param.get('measure_method') is not None else -1                # 评定算法（枚举值）：0:GUM,1:MCM  --必填
    factor = param.get('factor') if param.get('factor') is not None else ""                                             # 包含因子K（整数或小数）  --选择了GUM算法后，必填
    mcm_parameter_p = param.get('mcm_parameter_p') if param.get('mcm_parameter_p') is not None else ""                  # MCM参数：置信概率p，值如99.73%、99%、95%等   --选择了MCM算法后，必填
    mcm_exp_times = param.get('mcm_exp_times') if param.get('mcm_exp_times') is not None else ""                        # MCM实验次数，（非必填，从参数mcm_parameter_p可计算得来）

    is_perprocessed = int(param.get('is_perprocessed')) if param.get('is_perprocessed') is not None else 0              # 是否进行预处理：0:否；1:是

    save_flag = int(param.get('save_flag')) if param.get('save_flag') is not None else 1                                # 评定结果是否存库：0:未选;1:选中（默认存库）
    process_num = int(param.get('process_num')) if param.get('process_num') != None else 4                              # 默认4个进程同时读入文件

    data_level = int(param.get('data_level')) if param.get('data_level') is not None else 1                             # 默认为1，即L2数据

    # 检查参数合理性
    if file_path == "":
        return {"code": -1, "msg": "错误：路径参数不能为空！"}

    if os.path.isfile(file_path):
        return {"code": -1, "msg": "错误：路径参数不能为单个文件，需指定目录路径！"}

    file_list = [file_path]
    if checkFileIsRead(file_list) is False:
        print("错误：指定数据已有录入记录，或指定的路径/文件错误！")
        # 循环读取文件路径模式，这里不返回
        # return {"code": -1, "msg": "错误：指定数据已有录入记录，或指定的路径/文件错误！"}

    if measure_method == -1:
        print("请选择评定算法！")
        return {"code": -1, "msg": "请选择评定算法！"}
    elif measure_method == 1:
        if mcm_parameter_p == "":
            return {"code": -1, "msg": "参数值错误：MCM算法缺失参数p！"}
        if (str_to_float(mcm_parameter_p) - 1.0) > EPSINON or (str_to_float(mcm_parameter_p) - 0.0) < EPSINON:
            return {"code": -1, "msg": "参数值错误：MCM算法参数置信概率应大于0，小于1！"}

    # 开始准备参数，进行数据一键评定
    conf = {
        'TaskId': task_id,
        # 任务种类：0:数据录入；1:数据预处理；2:不确定度评定;3:数据分析数据处理;
        # 5:一键评定;6:评定结果查询（文件上传）；7:不确定度校验（文件上传）；8:数据比对不同设备；9:数据比对不同时间
        "TaskType": 5,

        "FilePath": file_path,
        "FileList": file_list,
        "DataGenerateSource": data_generate_source,
        "DataGenerateType": data_generate_type,
        'MeasurementMethod': measure_method,
        'Factor': str_to_float(factor),
        'McmParameterP': mcm_parameter_p,
        # 'McmParameterExpTimes': computeExperimentTimes(mcm_parameter_p) if mcm_exp_times == "" else str_to_float(mcm_exp_times),
        'McmParameterExpTimes': 0,
        "NeedPreprocessed": is_perprocessed,
        "SaveFlag": save_flag,
        "UserId": user_id,
        "ProcessNum": process_num,
        "DataLevel": data_level,
    }

    if measure_method == 1:
        conf['McmParameterExpTimes'] = computeExperimentTimes(mcm_parameter_p) if mcm_exp_times == "" else str_to_float(mcm_exp_times)
        print(conf)

    # 如果结果是保存到临时表，清除临时表
    if conf['SaveFlag'] == 0:
        print("清除临时表数据，准备本次数据保存..")
        # 清除临时表数据，参数和setTaskStatus中任务类型一致
        clear_db_temporary_table_and_keep_last_same_type_task(5)

    # 多线程开始一键评定
    # 设置任务开始
    # 设置本批次交互任务的ID
    TASK_ID = task_id
    if TASK_ID != "":
        ret = setTaskStatus(TASK_ID, conf['TaskType'], save_flag)
        if ret != "OK":
            print("setTaskStatus: %s" % ret)
            return ret

    processes = []
    process = multiprocessing.Process(target=preProcessDataFullProcess, args=(conf, TASK_ID))
    processes.append(process)
    process.start()

    return 0


def preProcessDataFullProcess(conf, TASK_ID):
    try:
        while True:
            processDataFullProcess(conf, TASK_ID)
            # x秒检查一次目录
            time.sleep(WaitTime)
    except Exception as e:
        print("runPreprocessTaskFunc_Error: %s" % e)
        setTaskStatusFinish(conf)
    print("收到界面暂定请求...")
    setTaskStatusFinish(conf)

def processDataFullProcess(conf, TASK_ID):
    # 获取所有读取的文件，避免重复读取文件
    #read_file_log = readFileLog()

    # [测试]检查算法是否请求停止（前台界面用户点击“暂停”按钮的响应）
    if isTaskStoped(TASK_ID, conf['TaskType']) == 1:
        exit()

    print("探测文件路径：%s" % conf['FileList'])
    # 1. 录入数据文件
    # processes = []
    # for file in conf['FileList']:
    #     print("输入参数：目录或文件：%s" % file)
    #     process = multiprocessing.Process(target=readFileOrDir, args=(file, read_file_log, conf['UserId'], TASK_ID))
    #     processes.append(process)
    #     process.start()
    q = multiprocessing.Queue()
    processes = []
    process = multiprocessing.Process(target=taskProcess, args=(conf['FileList'], conf['UserId'], conf['ProcessNum'], TASK_ID, q))
    processes.append(process)
    process.start()

    # 主进程等待子进程结束（阻塞执行）
    for proc in processes:
        proc.join()

    results = [q.get() for j in processes]
    print(results)
    # return 0
    if len(results) > 0 and results[0] == 0:
        print("未找到探测文件或探测文件已有录入记录！返回继续等待获取新探测文件..")
        return 0

    print("=============================================================")
    print("数据录入完成！")
    print("=============================================================")
    # return 0
    # 检查算法是否请求停止（前台界面用户点击“暂停”按钮的响应）
    if isTaskStoped(TASK_ID, conf['TaskType']) == 1:
        exit()

    # 2. 数据预处理
    # 获取预处理后的数据headId
    data_level = 1   # 默认获取L2数据

    # data_batch_info = getLatestDataBatchId(5)
    # if data_batch_info == "":
    #     print("错误：未找到最近录入的数据")
    #     return {"code": -1, "msg": "未找到最近录入的数据！"}
    # data_batch_id = data_batch_info[1]
    # print("data_batch_id: %s" % data_batch_id)

    data_head_id_list = getHeadIdByBatchId(TASK_ID, data_level, 0)
    if len(data_head_id_list) == 0:
        print("错误：未找到最近录入数据的head_id")
        return {"code": -1, "msg": "未找到最近录入数据的head_id！"}
    print("data_head_id_list: ")
    print(data_head_id_list)

    # 构造数据预处理参数
    # db_cols = ["HeadId", "Label", "Height", "Value", "IsAbnormal"]
    # db_cols = ["HeadId", "BatchId", "Label", "Height", "Value", "IsAbnormal", "ParameterSetting"]
    latest_conf = getLatestConfigParameterFromDb(0)
    if latest_conf == "":
        print("预处理配置参数获取有误，请确认单独运行过预处理任务！")
        return {"code": -1, "msg": "预处理配置参数获取有误，请确认单独运行过预处理任务！"}
    print(latest_conf)

    temperature_max = str_to_float(latest_conf['TemperatureMax'])
    temperature_min = str_to_float(latest_conf['TemperatureMin'])
    density_max = str_to_float(latest_conf['DensityMax'])
    density_min = str_to_float(latest_conf['DensityMin'])
    wind_speed_max = str_to_float(latest_conf['WindSpeedMax'])
    wind_speed_min = str_to_float(latest_conf['WindSpeedMin'])

    conf2 = {
        'ParameterSetting': latest_conf['Id'],
        'Type': latest_conf['Type'],
        'HeightStandardSet': latest_conf['HeightStandardSet'],
        'TimeStandardSet': latest_conf['TimeStandardSet'],
        'ExtremeValueCheck': latest_conf['ExtremeValueCheck'],
        'PhysicsConsistencyCheck': latest_conf['PhysicsConsistencyCheck'],
        'TimeConsistencyCheck': latest_conf['TimeConsistencyCheck'],
        'StatisticsCheck': latest_conf['StatisticsCheck'],
        'BoxplotCheck': latest_conf['BoxplotCheck'],
        # 'SaveFlag': ,     #
        'HeightReslution': int(latest_conf['HeightReslution']),
        # 'HeightReslutionStep': latest_conf['HeightReslutionStep'],
        'HeightReslutionUnit': int(latest_conf['HeightReslutionUnit']),
        'TimeReslution': int(latest_conf['TimeReslution']),
        # 'TimeReslutionStep': latest_conf['TimeReslutionStep],
        'TimeReslutionUnit': int(latest_conf['TimeReslutionUnit']),
        'TimeReslutionUnitOption': ['小时', '日', '周', '月', '季度', '年', '全时段'],
        'StatisticMethod': "0",           # 时间统一分辨率默认为0平均值计算

        'FilterRule': latest_conf['FilterRule'],
        'FilterRuleOption': ['', '拉伊达准则', '格拉布斯准则', '狄克逊准则', '稳健数据处理方法'],
        'ExceptionRule': latest_conf['ExceptionRule'],
        # 'DataSource': latest_conf['DataSource'],
        'DataSource': 3,                                                # 一键评定的数据来源为最近一次录入的数据
        'TemperatureMax': Decimal(latest_conf['TemperatureMax']),
        'TemperatureMin': Decimal(latest_conf['TemperatureMin']),
        'DensityMax': Decimal(latest_conf['DensityMax']),
        'DensityMin': Decimal(latest_conf['DensityMin']),
        'WindSpeedMax': Decimal(latest_conf['WindSpeedMax']),
        'WindSpeedMin': Decimal(latest_conf['WindSpeedMin']),
        'CheckTemperatureValue': 0 if (abs(temperature_max - 0.0) < EPSINON and abs(temperature_min - 0.0) < EPSINON) else 1,
        'CheckDensityValue': 0 if (abs(density_max - 0.0) < EPSINON and abs(density_min - 0.0) < EPSINON) else 1,
        'CheckWindSpeedValue': 0 if (abs(wind_speed_max - 0.0) < EPSINON and abs(wind_speed_min - 0.0) < EPSINON) else 1,

        'DbHeadTable': "",          # 数据筛选源Head表
        'DbTable': "",              # 数据筛选源Data表
        'DbSaveHeadTable': "",      # 数据存储Head表
        'DbSaveTable': "",          # 数据存储Data表
    }

    conf_all = dict(conf, **conf2)

    # 原始数据存在原始数据表
    conf_all['DbHeadTable'] = db_data_head_table
    conf_all['DbTable'] = db_raw_l2_data_table

    if conf_all['SaveFlag'] == 1:
        conf_all['DbSaveHeadTable'] = db_data_head_table
        conf_all['DbSaveTable'] = db_raw_l2_precessed_table
    else:
        conf_all['DbSaveHeadTable'] = db_temporary_data_head_table
        conf_all['DbSaveTable'] = db_temporary_data_table_l2

    print(conf_all)
    # return

    # 启动数据预处理进程
    processes = []
    process = multiprocessing.Process(target=preprocessProbeData, args=(data_head_id_list, conf_all, TASK_ID))
    # process = multiprocessing.Process(target=runPreprocessTask, args=(conf_all, TASK_ID))
    processes.append(process)
    process.start()

    # 主进程等待子进程结束（阻塞执行）
    for proc in processes:
        proc.join()

    print("=============================================================")
    print("数据预处理完成！")
    print("=============================================================")
    # 检查算法是否请求停止（前台界面用户点击“暂停”按钮的响应）
    if isTaskStoped(TASK_ID, conf['TaskType']) == 1:
        exit()

    # 3. 数据评定
    # 构造数据评定的参数
    conf3 = {
        'DataType': 1,
    }
    conf_all2 = dict(conf_all, **conf3)

    if conf_all2['SaveFlag'] == 1:
        # 原始数据存在原始数据表
        conf_all2['DbHeadTable'] = db_data_head_table
        conf_all2['DbTable'] = db_raw_l2_precessed_table

        conf_all2['DbSaveHeadTable'] = db_data_head_table
        conf_all2['DbSaveTable'] = db_raw_l2_precessed_table
    else:
        # 原始数据存在原始数据表
        conf_all2['DbHeadTable'] = db_temporary_data_head_table
        conf_all2['DbTable'] = db_temporary_data_table_l2

        conf_all2['DbSaveHeadTable'] = db_temporary_data_head_table
        conf_all2['DbSaveTable'] = db_temporary_data_table_l2

        # 特殊处理：如果筛选数据来自正式表，结果存储在临时表
        # 需要把更正正式表的data_head_id_list更新为临时表的data_head_id_list
        print("更新HeadIdList..")
        data_head_id_list = getHeadIdByBatchIdV3(conf_all2, TASK_ID, conf_all2['DataLevel'], 0)
        print(data_head_id_list)

    processes = []
    process = multiprocessing.Process(target=performUncertaintyAlgorithm, args=(data_head_id_list, conf_all2, TASK_ID))
    processes.append(process)
    process.start()

    # 主进程等待子进程结束（阻塞执行）
    for proc in processes:
        proc.join()

    print("=============================================================")
    print("数据评定完成！")
    print("=============================================================")


    # #设置任务结束
    # print("将要设置任务结束..")
    # if TASK_ID != "":
    #     print("设置任务结束！")
    #     updateTaskStatus(TASK_ID, conf['TaskType'])

    return 0


def checkFileIsRead(f_list):
    read_file_log = readFileLog()
    for file_path in f_list:
        if os.path.isfile(file_path):
            (filepath, tempfilename) = os.path.split(file_path)
            if tempfilename not in read_file_log:
                return True
        elif os.path.isdir(file_path):
            print("读取探测数据目录：%s" % file_path)
            for root, dirs, files in os.walk(file_path):
                for file in files:
                    if file not in read_file_log:
                        return True
        else:
            print("非文件或文件夹路径...")
            return False
    print("错误：未找到探测文件或探测文件已有录入记录！")
    return False
